package xpn.platform.modules.workflow.common;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
import org.springframework.data.rest.webmvc.RepositoryRestController;
import org.springframework.data.web.PagedResourcesAssembler;
import org.springframework.hateoas.PagedModel;
import org.springframework.web.bind.annotation.*;
import xpn.platform.common.config.XpnPlatformConfig;
import xpn.platform.modules.workflow.common.dto.UserDto;
import xpn.platform.modules.workflow.definition.action.Action;
import xpn.platform.modules.workflow.definition.action.ActionDAO;
import xpn.platform.modules.workflow.definition.state.StateDAO;
import xpn.platform.modules.workflow.runtime.history.History;
import xpn.platform.modules.workflow.runtime.history.HistoryDAO;
import xpn.platform.modules.workflow.runtime.instance.Instance;
import xpn.platform.modules.workflow.runtime.instance.InstanceDAO;
import xpn.platform.modules.workflow.runtime.todo.Todo;
import xpn.platform.modules.workflow.runtime.todo.TodoDTO;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;

/**
 * The type Workflow controller.
 */
@RepositoryRestController
@RestController
@RequestMapping("/api/workflow_service")
public class WorkflowController {

    @Autowired
    XpnPlatformConfig xpnPlatformConfig;

    @Autowired
    private WorkflowService workflowService;

    @Autowired
    private HistoryDAO historyDAO;

    @Autowired
    private ActionDAO actionDAO;

    @Autowired
    private StateDAO stateDAO;

    @Autowired
    InstanceDAO instanceDAO;

    @SuppressWarnings("rawtypes")
    @Autowired
    private PagedResourcesAssembler pagedResourcesAssembler;

    /**
     * 启动新流程实例
     *
     * @param no         流程定义编号
     * @param id         流程定义id
     * @param name       流程定义名称
     * @param starterId
     * @param entityLink 实体连接
     * @param refVarName 在规则引擎中注入的模型名称
     * @param parentInstanceId 父流程实例id
     * @param parentInstanceEntityLink 父流程实例表单连接
     * @return 创建成功的待办 persistent entity resource
     */
    @PostMapping(value = "instance")
    public TodoDTO startProcess(@RequestParam(defaultValue = "") String no, @RequestParam(defaultValue = "") Long id,
                                @RequestParam(defaultValue = "") String name, @RequestParam(defaultValue = "") String entityLink,
                                @RequestParam(defaultValue = "") String refVarName, @RequestParam String starterId,
                                @RequestParam(defaultValue = "") String parentInstanceId,
                                @RequestParam(defaultValue = "") String parentInstanceEntityLink,
                                HttpServletRequest request) {
        String xpnTokenName = xpnPlatformConfig.getSecurity().getAuthenticationTokenName();
        String token = request.getHeader(xpnTokenName);
        return workflowService.startProcess(id, name, no, starterId, xpnTokenName, token, entityLink, refVarName,parentInstanceId,parentInstanceEntityLink);
    }

    /**
     * 根据流程实例Id获取待办事项列表
     *
     * @param instanceId        流程实例Id
     * @param isCompleted       true 代表获取完成的待办事项列表，false 相反
     * @param param             the param
     * @param resourceAssembler the resource assembler
     * @return 待办事项列表 todos by executor id
     */
    @SuppressWarnings("unchecked")
    @GetMapping(value = "instance/{instanceId}/todos")
    public PagedModel<Todo> getTodosByInstanceId(@PathVariable Long instanceId, @RequestParam(required = false) Boolean isCompleted,
                                                     Pageable param, PersistentEntityResourceAssembler resourceAssembler) {
        Page<Todo> page = workflowService.getTodosByInstanceId(instanceId, isCompleted, param);
        return pagedResourcesAssembler.toModel(page, resourceAssembler);
    }

    /**
     * 根据执行者Id获取待办事项列表
     *
     * @param executorId        执行者Id
     * @param isCompleted       true 代表获取完成的待办事项列表，false 相反
     * @param param             the param
     * @param resourceAssembler the resource assembler
     * @return 待办事项列表 todos by executor id
     */
    @SuppressWarnings("unchecked")
    @GetMapping(value = "todos")
    public PagedModel<Todo> getTodosByExecutorId(@RequestParam String executorId, @RequestParam boolean isCompleted,
                                                     Pageable param, PersistentEntityResourceAssembler resourceAssembler) {
        Page<Todo> page = workflowService.getTodosByExecutorId(executorId, isCompleted, param);
        return pagedResourcesAssembler.toModel(page, resourceAssembler);
    }

    /**
     * 获取执行者在指定流程实例中的所有待办事项列表
     *
     * @param executorId        执行者Id
     * @param instanceId        流程实例Id
     * @param isCompleted       true 代表获取完成的待办事项列表，false 相反
     * @param todoId            待办事项Id
     * @param entityLink        实体连接
     * @param refVarName        在规则引擎中注入的模型名称
     * @param param             the param
     * @param resourceAssembler the resource assembler
     * @return 待办事项列表 todos by executor and instance
     */
    @GetMapping(value = "instance/{instanceId}/todos/self")
    public List<TodoDTO> getTodosByExecutorAndInstance(@RequestParam(defaultValue = "") String executorId,
                                                       @PathVariable Long instanceId, @RequestParam(defaultValue = "false") boolean isCompleted,
                                                       @RequestParam(defaultValue = "") Long todoId, @RequestParam(defaultValue = "") String entityLink,
                                                       @RequestParam(defaultValue = "") String refVarName, Pageable param,
                                                       PersistentEntityResourceAssembler resourceAssembler, HttpServletRequest request) {
        String xpnTokenName = xpnPlatformConfig.getSecurity().getAuthenticationTokenName();
        String token = request.getHeader(xpnTokenName);
        return workflowService.getTodosByExecutorAndInstance(executorId, instanceId, todoId, isCompleted, entityLink, refVarName, xpnTokenName, token);
    }

    /**
     * 结束待办
     *
     * @param executorId 执行者Id
     * @param todoId     待办事项Id
     * @param actionId   操作id
     * @return 待办
     */
    @PostMapping(value = "instance/todos/{todoId}/complete")
    public Todo completeTodo(@RequestParam String executorId,
                             @PathVariable Long todoId,
                             @RequestParam(required = false) Long actionId,
                             HttpServletRequest request) {
        String xpnTokenName = xpnPlatformConfig.getSecurity().getAuthenticationTokenName();
        String token = request.getHeader(xpnTokenName);
        return workflowService.completeTodo(todoId, executorId, actionId, xpnTokenName, token);
    }

    /**
     * 已办转待办
     *
     * @param executorId 执行者Id
     * @param todoId     待办事项Id
     * @param actionId   操作id
     * @return 待办
     */
    @PostMapping(value = "instance/todos/{todoId}/incomplete")
    public Todo doneToTodo(@RequestParam String executorId,
                             @PathVariable Long todoId,
                             @RequestParam(required = false) Long actionId,
                             HttpServletRequest request) {
        String xpnTokenName = xpnPlatformConfig.getSecurity().getAuthenticationTokenName();
        String token = request.getHeader(xpnTokenName);
        return workflowService.doneToTodo(todoId, executorId, actionId, xpnTokenName, token);
    }


    /**
     * 执行一个操作
     *
     * @param todoId        执行者的待办事项Id
     * @param actionId      执行的操作Id
     * @param comment       填写意见操作所需要的具体数据
     *                      requestBody sendees 发送人列表
     * @param entityLink     实体连接
     */
    @PostMapping(value = "instance/todos/{todoId}/actions/{actionId}/execute")
    public Object execute(@PathVariable Long todoId,
                        @PathVariable Long actionId,
                        @RequestParam(defaultValue = "") String comment,
                        @RequestParam(required = false) String entityLink,
                        @RequestParam(required = false,defaultValue = "") Long commentActionId,
                        @RequestParam(required = false,defaultValue = "") Long stateId,
                        @RequestParam(required = false,defaultValue = "") String actionName,
                        HttpServletRequest request) throws IOException {
        String xpnTokenName = xpnPlatformConfig.getSecurity().getAuthenticationTokenName();
        String token = request.getHeader(xpnTokenName);
        String sendeesObjString = IOUtils.toString(request.getInputStream(),"utf-8");
        JsonObject json=new JsonParser().parse(sendeesObjString).getAsJsonObject();
        if(json.has("actionName")){
            actionName=json.get("actionName").toString();
        }
        if(json.has("entityLink")){
            entityLink=json.get("entityLink").getAsString();
        }
        if(json.has("comment")){
            comment=json.get("comment").getAsString();
        }
        if(json.has("commentActionId")){
            commentActionId=json.get("commentActionId").getAsLong();
        }
        JsonArray sendees = new JsonParser().parse(sendeesObjString).getAsJsonObject().getAsJsonArray("sendees");
        return workflowService.execute(todoId, actionId, sendees, comment,xpnTokenName, token,commentActionId,entityLink,stateId,actionName);
    }

    /**
     * 查询指定已办可收回的列表，空列表代表不可收回
     *
     * @param todoId 已办Id
     * @return 可收回的 History 列表
     */
    @GetMapping(value = "queryTakeBack")
    public List<History> queryTakeBack(@RequestParam Long todoId) {
        List<History> histories = workflowService.queryTakeBack(todoId);
        return histories;
    }

    /**
     * 执行收回操作(收回所有待办)
     *
     * @param todoId the todoId
     */
    @PostMapping(value = "takeBackAllTodo")
    public String takeBackAllTodo(@RequestParam Long todoId, HttpServletRequest request) {
        String xpnTokenName = xpnPlatformConfig.getSecurity().getAuthenticationTokenName();
        String token = request.getHeader(xpnTokenName);
        workflowService.takeBackAllTodo(todoId, xpnTokenName, token);
        return "tackBackSuccess";
    }

    /**
     * 执行收回操作
     *
     * @param historyId the history id
     */
    @PostMapping(value = "takeBack")
    public void takeBack(@RequestParam Long historyId, HttpServletRequest request) {
        String xpnTokenName = xpnPlatformConfig.getSecurity().getAuthenticationTokenName();
        String token = request.getHeader(xpnTokenName);
        workflowService.takeBack(historyId, xpnTokenName, token);
    }

    /**
     * 根据流程实例查找流程记录列表
     *
     * @param instanceId 流程实例Id
     * @return 流程记录列表
     */
    @GetMapping(value = "instance/{instanceId}/histories")
    public List<History> findHistoriesByInstanceId(@PathVariable Long instanceId) {
        return historyDAO.findByInstanceIdOrderByCreatedTime(instanceId);
    }

    /**
     * 根据状态查找操作
     *
     * @param stateId 状态Id
     * @return 操作列表
     */
    @GetMapping(value = "state/{stateId}/actions")
    public List<Action> findActionsByState(@PathVariable Long stateId) {
        List<Action> actions = actionDAO.findByStateOrderBySortNo(stateDAO.getOne(stateId));
        return actions;
    }

    /**
     * 通过oldId获取流程实例
     *
     * @param oldId the history id
     */
    @GetMapping(value = "get_by_old_id")
    public Instance getByOldId(@RequestParam String oldId) {
        return instanceDAO.findFirstByOldId(oldId);
    }

    /**
     * 通过oldId获取流程实例
     *
     * @param id the history id
     */
    @GetMapping(value = "get_instance_by_id")
    public Instance getInstanceById(@RequestParam Long id) {
        return instanceDAO.getById(id);
    }

    /**
     * 通过代办事项id获取可以退回的人员信息。
     *
     * @param todoId     待办事项Id
     * @return 待办
     */
    @GetMapping(value = "instance/todos/{todoId}/goBackUser")
    public List<UserDto> getGoBackUser(@PathVariable Long todoId) {
        return workflowService.getGoBackUser(todoId);
    }

    /**
     * 通过代办事项id获取返回发送人的人员信息。
     *
     * @param todoId     待办事项Id
     * @return 待办
     */
    @GetMapping(value = "instance/todos/{todoId}/returnSenderUser")
    public List<UserDto> returnSenderUser(@PathVariable Long todoId) {
        return workflowService.returnSenderUser(todoId);
    }
}
